// 导入所需的 NestJS 依赖
import { Injectable, NotFoundException } from '@nestjs/common';
// 导入 Node.js 的 path 模块，用于处理文件路径
import { join } from 'path';
// 导入 Node.js 的文件系统模块，包括同步和异步操作
import { existsSync, promises as fsPromises } from 'fs';
// 导入文件信息接口定义
import { FileInfo } from './interfaces/file-info.interface';
// 导入上传响应数据传输对象
import { UploadResponseDto } from './dto/upload-response.dto';
// 导入 UUID 生成函数
import { v4 as uuidv4 } from 'uuid';
// 导入配置服务
import { ConfigService } from '@nestjs/config';

// 标记为可注入的服务类
@Injectable()
export class FileService {
  // 文件上传目录路径
  private readonly uploadDir: string;
  // 文件数据库JSON文件路径
  private readonly dbFilePath: string;

  // 构造函数，注入配置服务
  constructor(private configService: ConfigService) {
    // 初始化上传目录路径，从配置中获取或使用默认值
    this.uploadDir = join(process.cwd(), this.configService.get('UPLOAD_DIR', 'uploads'));
    // 初始化数据库文件路径
    this.dbFilePath = join(this.uploadDir, 'files-db.json');
    // 确保上传目录存在
    this.ensureUploadDirExists();
    // 确保数据库文件存在
    this.ensureDbFileExists();
  }

  // 确保上传目录存在的私有方法
  private async ensureUploadDirExists() {
    try {
      // 创建目录，如果不存在则递归创建
      await fsPromises.mkdir(this.uploadDir, { recursive: true });
    } catch (error) {
      // 如果创建失败，记录错误
      console.error('Error creating upload directory:', error);
    }
  }

  // 确保数据库文件存在的私有方法
  private async ensureDbFileExists() {
    // 检查数据库文件是否存在
    if (!existsSync(this.dbFilePath)) {
      // 如果不存在，创建一个空数组作为初始数据
      await fsPromises.writeFile(this.dbFilePath, JSON.stringify([]));
    }
  }

  // 获取文件数据库内容的私有方法
  private async getFilesDb(): Promise<FileInfo[]> {
    try {
      // 读取数据库文件内容
      const data = await fsPromises.readFile(this.dbFilePath, 'utf8');
      // 解析JSON数据并返回
      return JSON.parse(data);
    } catch (error) {
      // 如果读取失败，记录错误并返回空数组
      console.error('Error reading files database:', error);
      return [];
    }
  }

  // 保存文件数据库内容的私有方法
  private async saveFilesDb(files: FileInfo[]): Promise<void> {
    try {
      // 将文件信息数组保存到数据库文件
      await fsPromises.writeFile(this.dbFilePath, JSON.stringify(files, null, 2));
    } catch (error) {
      // 如果保存失败，记录错误
      console.error('Error saving files database:', error);
    }
  }

  // 保存上传文件信息的公共方法
  async saveFile(file: Express.Multer.File): Promise<UploadResponseDto> {
    // 生成唯一文件ID
    const fileId = uuidv4();
    // 创建文件信息对象
    const fileInfo: FileInfo = {
      id: fileId,
      filename: file.filename,
      originalname: file.originalname,
      mimetype: file.mimetype,
      size: file.size,
      uploadDate: new Date(),
      path: join(this.uploadDir, file.filename),
    };

    // 获取现有文件列表
    const files = await this.getFilesDb();
    // 添加新文件信息
    files.push(fileInfo);
    // 保存更新后的文件列表
    await this.saveFilesDb(files);

    // 创建并填充响应对象
    const response = new UploadResponseDto();
    response.filename = file.filename;
    response.originalname = file.originalname;
    response.mimetype = file.mimetype;
    response.size = file.size;
    response.url = `/files/download/${file.filename}`;

    return response;
  }

  // 获取指定文件信息的公共方法
  async getFileInfo(filename: string): Promise<FileInfo> {
    // 获取所有文件信息
    const files = await this.getFilesDb();
    // 查找指定文件
    const fileInfo = files.find((file) => file.filename === filename);

    // 如果文件不存在，抛出异常
    if (!fileInfo) {
      throw new NotFoundException(`File with filename ${filename} not found`);
    }

    return fileInfo;
  }

  // 获取所有文件列表的公共方法
  async listAllFiles(): Promise<UploadResponseDto[]> {
    // 获取所有文件信息
    const files = await this.getFilesDb();
    // 将文件信息转换为响应格式并返回
    return files.map((file) => ({
      filename: file.filename,
      originalname: file.originalname,
      mimetype: file.mimetype,
      size: file.size,
      url: `/files/download/${file.filename}`,
    }));
  }
}
